#include "config.h"
#include <string.h>
#include "usart.h"
#include "stm32f1xx_hal.h"

#define INIT_CODE 0x19930613

//2kb eeprom  4page 512b

#define FLASH_UserInfoAddr (1024 * (120 + 0)) /*! usr info config address */

/*!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
static void mcu_flash_read(uint32_t addr, uint8_t* pdata, uint16_t size)
{
    __IO uint8_t* psrc;
    psrc = (__IO uint8_t*)(addr);
    while (size) {
        size--;
        *pdata = *(psrc);
        pdata++;
        psrc++;
    }
}

/*!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
static void mcu_flash_write(uint32_t addr, uint32_t* pdata, uint16_t size)
{
    HAL_StatusTypeDef res;
    uint16_t          i;
    __IO uint32_t* psrc;
    psrc = (__IO uint32_t*)(addr);

    /*! 4byte write bug fixed */
    if (0 == size % 4) {
        size = size / 4;
    } else {
        size = size / 4 + 1;
    };

    res = HAL_FLASH_Unlock();
    if (res == HAL_OK) {
        //1.erase
        for (i = 0; i < size; i++) {
            if (*psrc != 0xFFFFFFFF) {
                FLASH_PageErase((uint32_t)psrc);
                res = FLASH_WaitForLastOperation((uint32_t)FLASH_TIMEOUT_VALUE);
                CLEAR_BIT(FLASH->CR, FLASH_CR_PER);
            }
            psrc++;
        }
        //2.write
        while (size) {
            res = HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, addr, *pdata);
            pdata++;
            addr += 4;
            size--;
        }
    }
    HAL_FLASH_Lock();
}

eeprom_save_t   eeprom_config = { 0 };
config_status_e config_status = IDLE;

void save_config(void)
{
    mcu_flash_write(FLASH_UserInfoAddr, (uint32_t*)&eeprom_config, sizeof(eeprom_config));
}

void config_set_valid(void)
{
    eeprom_config.code = INIT_CODE;
}

uint8_t read_config(void)
{
    memset(&eeprom_config, 0, sizeof(eeprom_config));
    mcu_flash_read(FLASH_UserInfoAddr, (uint32_t*)&eeprom_config, sizeof(eeprom_config));
    if (INIT_CODE != eeprom_config.code) {
        config_status = CONFIG_INVALID;
        eeprom_config.valid = 0;
        msg_printf("first power on, invalid config\r\n");
        return 0;
    }
    config_status = NORMAL;
    return 1;
}
